Decorator 와의 싸움
Decorator 개념
기존의 함수에 여러가지 기능을 추가하는 파이썬 구문이라고 한다.
어떤 함수실행에 앞이나 뒤에 원하는 코드(함수)들이 같이 실행되도록 할 수 있다!
함수 또는 함수의 인자들을 활용 할 수도 있다.
fnA() ⇒ fnB ⇒ …fnN
Decorator 샘플 코드
def decorator_function(original_function): #1
def wrapper_function(): #5
return original_function() #7
return wrapper_function #6
def display(): #2
print 'display 함수가 실행됐습니다.' #8
decorated_display = decorator_function(display) #3
decorated_display() #4
'display 함수가 실행됐습니다.'#9
- decorator_function 정의
- display 정의
- decorateddisplay라는 변수에 display 함수를 인자로 가진 decoratorfunction을 실행한 리턴값을 할당(리턴값은 wrapper_function 아직 실행되지 않음 )
- decorateddisplay()를 통해 wrapperfunction을 호출
- wrapper_function 정의
- wrapper_function 호출
- original_function(=display) ()
- 문자열 출력
Decorator Why?
def decorator_function(original_function): #1
def wrapper_function(): #5
실행시키길 원하는 코드1111 #7
return original_function() #8
실행시키길 원하는 코드2222 #9
return wrapper_function #6
def display(): #2
print 'display 함수가 실행됐습니다.' #8
decorated_display = decorator_function(display) #3
decorated_display() #4
실행시키길 원하는 코드 1111 #10
'display 함수가 실행됐습니다.'#11
실행시키길 원하는 코드 2222 #12
위와 같이 내가 함수 실행에 내가 원하는 코드를 엮을 수 있다.
그럼 그냥 함수 하나로 짜면 안돼?
- 중복되는 부분을 함수에서 분리시켜 코드를 줄일 수 있다.
- 그 외의 장점은… 생각해봐야겠다.
위의 방법을 줄일 수 있는 방법이 있다! @심벌 사용하기
# -*- coding: utf-8 -*-
def decorator_function(original_function):
def wrapper_function():
print f'{original_function.__name__} 함수가 호출되기전 입니다.'
return original_function()
return wrapper_function
@decorator_function #1
def display_1():
print 'display_1 함수가 실행됐습니다.'
@decorator_function #2
def display_2():
print 'display_2 함수가 실행됐습니다.'
# display_1 = decorator_function(display_1) #3
# display_2 = decorator_function(display_2) #4
display_1()
display_2()
'display_1 함수가 실행됐습니다.'
'display_2 함수가 실행됐습니다.'
변수를 붙이고 실행 시키는 대신 @심벌을 데코레이션 함수와 함수 정의에 붙여 준다.
그럼 동일한 결과를 얻는다 .
Decorator 실전
original_function의 인자가 있을 경우
def decorator_function(original_function):
def wrapper_function(*args, **kwargs): #1
print f'{original_function.__name__} 함수가 호출되기전 입니다.'
return original_function(*args, **kwargs) #2
return wrapper_function
@decorator_function
def display():
print 'display 함수가 실행됐습니다.'
@decorator_function
def display_info(name, age):
print "display_info({name}, {}) 함수가 실행됐습니다."
display()
print
display_info('John', 25)
"display_info 함수가 호출되기전 입니다."
"display_info(John, 25) 함수가 실행됐습니다."
display 함수가 인자 (name, age)를 받을 경우에는 wrapper 함수와 original_function에 인자를 설정해줘서 인자가 전달 될 수 있도록 한다. *args, **kwargs 를 같이 써줘야 유동적으로 인자를 받을 수 있다.
Decorator에 parameter 집어넣기
그리고 decorator_function에도 parameter를 집어 넣는 것도 가능하다!
# 1. 데코레이터를 데코레이터 해놓기- 이렇게 함으로써 데코레이터가 함수이외의 인자를 넣을수 있는 자리를 만들어 준다.
def parametrized(dec):
def layer(*args, **kwargs):
def repl(f):
return dec(f, *args, **kwargs)
return repl
return layer
@parametrized
def decorator_function(original_function,paramofDeco):
def wrapper_function():
print f'{original_function.__name__} 함수가 호출되기전 입니다.'
return original_function() + paramofDeco
return wrapper_function
@decorator_function(paramofDeco)
def display_3():
print 'display_3 함수가 실행됐습니다.decorator_function() 인자는 '
display_3()
'display_3 함수가 호출되기전 입니다.'
'display_3 함수가 실행됐습니다.decorator_function() 인자는 paramofDeco'
# 2. 데코레이터를 한번 더 싸기
def deco_decorator_function(paramofDeco):
def decorator_function(func):
def wrapper():
print f'{original_function.__name__} 함수가 호출되기전 입니다.'
result = func()
return result + paramofDeco
return wrapper
return decorator_function
@deco_decorator_function(paramofDeco)
def display_4():
print 'display_4 함수가 실행됐습니다.decorator_function() 인자는 '
display_4()
'display_4 함수가 호출되기전 입니다.'
'display_4 함수가 실행됐습니다.decorator_function() 인자는 paramofDeco'
1의 방법은 한번 만들어 놓으면 @심벌로 다른 데코레이터 함수들선언시에 parameter를 쉽게 받을 수 있도록 할 수 있다. (코드 1줄 줄일 수 있네. n번 늘어나면 n줄 Save! )
2의 방법은 그때 그때 적용
*주의사항 데코레이터 함수가 parameter 값을 받도록 설정했을때, 만약 paremeter값을 받지 않아도 실행코드 ” () ” 만들어 놔야한다. 안그러면 실행이 되지 않는다. (파라미터값을 넣고 데코레이터 실행한다는걸로 코드가 작성되었기 때문이다.
#위의 데코레이션을 사용한다고 가정했을때
@deco_decorator_function
def display_5():
print " something "
display_5()
##실행에러
@deco_decorator_function()
def display_6():
print "something"
display_6()
"something"